﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework.Content;


using System.Threading;

using FXnaEngine.Compositor;

using FXnaEngine.Interfaces;

using FXnaEngine.Graphics;

using FXnaEngine.Input;







namespace FXnaEngine
{


    public delegate void EngineMessageHandler(IMessage message);

  

    /// <summary>
    /// 要求作用类似于gamecomponent
    /// 同时支持game，以及控件应用
    /// </summary>
    public  class FGame:BaseGame
    {

        #region construct

        public FGame()
        {






            managers = new List<BaseManager>();
         
            
            



        }
        #endregion

        #region 事件模型

        /// <summary>
        /// This event is raised when there are messages in the queue
        /// </summary>
        /// <remarks>
        /// The message is only raised during a update loop
        /// </remarks>
        public event EngineMessageHandler GameMessage;

        /// <summary>
        /// This event is raised when the game is exiting.
        /// </summary>
        public event EventHandler<EventArgs> GameExiting;



        #endregion

        #region field

     

     

       






         public const int UniqueIDEmpty = -1;
         public const int TemplateIDEmpty = -1;
         public const int TemplateIDCustom = 0; // This ID is given to any objects loaded manually rather than from a template definition.
         public const int SceneMgrRootEntityID = 0;
         public const int FirstEntityIDAbleToBeAltered = 2;    // No entity with an ID less than 2 is allowed to be deleted, unless the engine is shutting down


         #region 消息循环系统

         private static readonly object messageLock = new object();

         private readonly List<BaseManager> managers;

         internal List<IMessage> currentMessages;
         private bool exiting = false;
         internal List<IMessage> queuedMessages;
         internal List<IMessage> handledMessages;

#endregion





        


     
  

    
  




         public float PartialSecondsThisFrame
         {
             get { return partialSecondsThisFrame; }
         }
         private float partialSecondsThisFrame;

         public uint MessagesSentThisFrame
         {
             get { return messagesSentThisFrame; }
         }
         private uint messagesSentThisFrame;

         /// <summary>
         /// Should only be 'set' by <see cref="TerrainComponent"/>.
         /// </summary>
         public Int64 TerrainID
         {
             get { return terrainID; }
             set { terrainID = value; }
         }
         private Int64 terrainID = -1;

         // @TODO: Move this to graphics system or something
         public bool DrawShadowMapTextureToScreen
         {
             get { return drawShadowMapTextureToScreen; }
             set { drawShadowMapTextureToScreen = value; }
         }
         private bool drawShadowMapTextureToScreen;

     





         /// <summary>
         /// Stores whether or not the game has loaded content at least once.
         /// </summary>
         private bool contentLoadedOnce = false;
         public bool ContentLoadedOnce
         {
             get { return contentLoadedOnce; }
         }





        #endregion

         #region 私有属性
        
 

        #endregion

         #region 公共属性




         /// <summary>
         /// Gets the settings for the game.
         /// </summary>
         /// <remarks>
         /// Inheritors can use this property to set the settings instance.
         /// </remarks>
         public Settings Settings
         {
             get { return this.settings; }
             protected set { this.settings = value; }
         }
         private Settings settings;




     


         /// <summary>
         /// Retrieves the compositor.
         /// </summary>
         public ScreenCompositor Compositor
         {
             get
             {
                 return

                     this.Services.GetService(typeof(ScreenCompositor)) as ScreenCompositor;
                }
         }



         /// <summary>
         /// Retrieves the global configuration manager.
         /// </summary>
         /// <remarks>Returns null if the manager has not been initialized yet.</remarks>
         public ConfigurationManager ConfigurationManager
         {
             get
             {
                 return this.Services.GetService(typeof(ConfigurationManager)) as ConfigurationManager;
             }
         }








         public FGraphicsSystem Graphics
         {

             get
             {
                 return this.Services.GetService(typeof(FGraphicsSystem)) as FGraphicsSystem;
             }
 
         }


         /// <summary>
         /// Gets the <see cref="SceneManager"/>
         /// </summary>
         /// <remarks>Returns null if the manager has not been initialized yet.</remarks>
         public FSceneManger SceneManager
         {
             get
             {
                 return this.Services.GetService(typeof(FSceneManger)) as FSceneManger;
             }
         }


         /// <summary>
         /// Retrieves the physics system.
         /// </summary>
         /// <remarks>Returns null if the system has not been initialized yet.</remarks>
         public PhysicsManager Physics
         {
             get
             {
                 return this.Services.GetService(typeof(PhysicsManager)) as PhysicsManager;
             }
         }



         #endregion



         #region 私有方法

         



         #endregion




        #region 公共函数


         #region 程序运行顺序逻辑

         public override void InitEngine(IGraphicsDeviceService graphics, ContentManager content, GameServiceContainer services)
         {
             base.InitEngine(graphics, content, services);


             //初始化对应的系统服务,主要用于公共访问


             this.Services.AddService(typeof(ConfigurationManager), new ConfigurationManager());
        
             this.Services.AddService(typeof(ScreenCompositor) ,new ScreenCompositor(this));


      

             this.Services.AddService(typeof(FSceneManger), new FSceneManger(this));



             this.Services.AddService(typeof(FGraphicsSystem), new FGraphicsSystem(this));






             // Other services loaded via Configuration.XML file, which is located in
             // ./framework/code/common (not included in the project itself, you have
             // to browse there manually)
             //针对配置文件中的service,需要动态加载，目前尚无此机制


             //初始化对应的消息模型

             this.currentMessages = new List<IMessage>();
             this.queuedMessages = new List<IMessage>();
             this.handledMessages = new List<IMessage>();



             //this.managers = new List<BaseManager>();




             //初始化其他管理器等

             this.InitializeSettings();

             this.InitializeManagers();





         }


        /// <summary>
        /// 设计用于销毁对象
        /// </summary>
         public void Dispose()
         {


 
         }
    

         public virtual void Initialize()
         {

             // Set up screen compositor            
             this.Compositor.InsertScreen(new FPSScreen(10, 10, this), false);






         }




         /// <summary>
         /// Initializes the game settings
         /// </summary>
         protected virtual void InitializeSettings()
         {

             //this.Settings = this.Content.Load<Settings>("Settings");

             //暂时不启用这一能力

             this.settings = new Settings(this);

         }


         /// <summary>
         /// Initializes the input managers
         /// </summary>
         private void InitializeManagers()
         {


             //暂时性取消动态加载部分，为了方便调试


//             this.managers.AddRange(this.ConfigurationManager.GetManagers(this, ConfigurationManager.SectionManagers));

//#if WINDOWS
//             // Load managers that exist only on the windows platform
//             this.managers.AddRange(this.ConfigurationManager.GetManagers(this, ConfigurationManager.SectionWindowsOnlyManagers));
//#endif //WINDOWS


             //手动加入一些管理器
             //鼠标和键盘控制


             PhysicsManager pm = new FXnaEngine.Physics.JigLibXPhysicsManager(this);

             this.managers.Add(pm);





            



             //加入输入控制

             InputManager im = new InputManager(this);
             this.managers.Add(im);
             
             






             this.managers.Sort(delegate(BaseManager left, BaseManager right)
             {
                 return right.UpdateOrder.CompareTo(left.UpdateOrder);
             });

             for (int i = this.managers.Count - 1; i >= 0; --i)
             {
                 BaseManager manager = this.managers[i];
                 manager.Initialize();
             }





         }





    



       
        
       /// <summary>
       /// 加载系统级资源
       /// </summary>
        public void LoadContent()
        {
            this.Content.RootDirectory = "Content";


          

            this.Graphics.LoadContent();


            this.Compositor.LoadContent(contentLoadedOnce);

            this.SceneManager.LoadContent(contentLoadedOnce, this.Content, false);

           


            contentLoadedOnce = true;

        }




        /// <summary>
        /// 卸载系统级资源
        /// </summary>
        public void UnloadContent()
        {

            this.SceneManager.UnloadContent();

            this.Compositor.UnloadContent();

         


        }


        /// <summary>
        /// 核心绘制程序
        /// </summary>
        /// <param name="gameTime"></param>
        public void Draw(GameTime gameTime)
        {


            this.Graphics.DrawFrame(null,gameTime);


            ////绘制主要三维系统

            //this.SceneManager.Draw(gameTime);





            ////绘制屏幕信息

            this.Compositor.DrawCompositorChain(gameTime);

       


        }


        /// <summary>
        /// Updates all game and engine logic for one frame.
        /// </summary>
        /// <param name="gameTime">Time snapshot for the current update.</param>
        public void Update(GameTime gameTime)
        {

            //记录消息发送数量

            this.messagesSentThisFrame = 0;

            //更新时间

            this.GameTime = gameTime;


            this.partialSecondsThisFrame = (float)(Math.Max(gameTime.ElapsedGameTime.Ticks, 1u) * 0.0000001f);


            ///如果正在执行退出逻辑
            ///
            if (this.exiting == true)
            {
                // Clear all other messages
                this.currentMessages.Clear();
                this.queuedMessages.Clear();
                this.handledMessages.Clear();

                // Send a single shutdown message to all, bypass the pool as we are shutting down    
            
                //发送关闭消息

                //this.SceneManager.Shutdown();



                // Empty out the pool
                ObjectPool.ReleaseAll();



                // Raise the exit event
                //内部消息，与公共消息的关系

                this.OnGameExiting();


               
                //控件关闭

                //this.Exit();


                return;
            }

            //在此处理所有的消息

            this.HandleMessages();



            //处理场景更新

            this.SceneManager.Update(gameTime);


            //测试在代码，测试新的绘图系统

            this.Graphics.Update(gameTime);



            //更新所有的内部组件

            for (int i = this.managers.Count - 1; i >= 0; --i)
            {
                if (this.managers[i].Enabled)
                {
                    this.managers[i].Update(gameTime);
                }
            }

        }

        /// <summary>
        /// Raises the <see cref="GameExiting"/> event
        /// </summary>
        protected virtual void OnGameExiting()
        {
            if (this.GameExiting != null)
            {
                this.GameExiting(this, EventArgs.Empty);
            }
        }



#endregion


        #region 消息处理单元


        private bool PreProcessMessage(IMessage message)
        {
            switch (message.Type)
            {
                case MessageType.Unknown:
                    {
                        throw new Exception("Message must be given a type");
                    }
                case MessageType.Shutdown:
                    {
                        // @TODO: Rather than simply closing the program, we should notify all systems and let
                        //          them shutdown first in case they'd like to do something like save data.
                        this.exiting = true;
                        return false;
                    }
                default:
                    break;
            }

            return true;
        }

        public void QueueMessage(IMessage message)
        {
            if (!PreProcessMessage(message))
                return;

            if (message.Protocol == MessageProtocol.Request)
            {
                throw new Exception("Messages with 'Request' message protocols cannot be queued, as they must return results immediately");
            }

            // Lock the message queue before adding message
            lock (FGame.messageLock)
            {
                this.queuedMessages.Add(message);
            }
        }

        /// <summary>
        /// Sends messages to the system
        /// </summary>
        /// <param name="message">The <see cref="IMessage"/> which should be send</param>
        /// <returns>Returns whether or not the message made it to the entity</returns>
        /// <remarks>Use <see cref="Message<T>"/> when sending errors</remarks>
        public bool SendMessage(IMessage message)
        {
            ++this.messagesSentThisFrame;

            if (!PreProcessMessage(message))
                return false;

            bool result = this.OnGameMessage(message);

            ProcessMessageHandled(message);

            return result;
        }

        public void ProcessMessageHandled(IMessage message)
        {
            if (!message.GetHandled())
            {
                lock (FGame.messageLock)
                {
                    message.SetHandled(true);
                    this.handledMessages.Add(message);
                }
            }
            else
            {
                throw new Exception("Message was improperly sent. Did you send the same message twice without re-aquiring memory for it from the ObjectPool?");
            }
        }




        /// <summary>
        /// Sends messages to all registered QSInterface instances only.
        /// </summary>
        /// <param name="message">The <see cref="IMessage"/> which should be sent</param>
        /// <param name="interfaceYype">The <see cref="InterfaceType"/> to send the message to</param>
        /// <remarks>Use <see cref="Message<T>"/> when sending errors</remarks>
        public void SendInterfaceMessage(IMessage message, InterfaceType interfaceType)
        {
          
            //++this.messagesSentThisFrame;

            //SceneManager sceneMgr = this.SceneManager;
            //if (sceneMgr != null)
            //{
            //    if (!sceneMgr.ForwardInterfaceMessage(message, interfaceType))
            //    {
            //        throw new Exception("The interface does not yet exist, hasn't been initialized with the scene manager, or didn't handle the message type it was sent.");
            //    }

            //    ProcessMessageHandled(message);
            //}



        }



        /// <summary>
        /// Raises the <see cref="GameMessage"/> event
        /// </summary>
        /// <param name="message">The <see cref="IMessage"/> to raise</param>
        protected virtual bool OnGameMessage(IMessage message)
        {
            if (this.GameMessage == null)
                return false;

            if (message.UniqueTarget == UniqueIDEmpty)
            {
                this.GameMessage(message);
            }
            else
            {


                //Entity target;

                //if (this.SceneManager.Entities.TryGetValue(message.UniqueTarget, out target))
                //{
                //    target.ExecuteMessage(message);
                //}
                //else
                //{
                //    // Target not found
                //    return false;
                //}




            }

            return true;
        }


        /// <summary>
        /// Clears the list of messages and release the aquired messages
        /// </summary>
        /// <param name="list">List of <see cref="IMessage"/> to be cleared</param>
        private static void ClearMessages(IList<IMessage> list)
        {
            while (list.Count > 0)
            {
                IMessage message = list[0];
                list.RemoveAt(0);

                ObjectPool.Release(message);
            }
        }

        /// <summary>
        /// This handles messages and raises the <see cref="QSGame.GameMessage"/> if needed
        /// 总的消息处理接口函数
        /// </summary>
        private void HandleMessages()
        {
            if (this.GameMessage != null)
            {
                lock (messageLock)
                {
                    List<IMessage> temp = this.currentMessages;
                    this.currentMessages = this.queuedMessages;
                    this.queuedMessages = temp;
                    this.queuedMessages.Clear();
                }

                for (int i = 0; i < this.currentMessages.Count; ++i)
                {
                    if (this.exiting == true)
                    {
                        break;
                    }

                    // Send message to entire system
                    this.OnGameMessage(this.currentMessages[i]);
                }
            }

            ClearMessages(this.currentMessages);

            if (this.GameMessage != null)
            {
                lock (messageLock)
                {
                    List<IMessage> tempHandled = this.currentMessages;
                    this.currentMessages = this.handledMessages;
                    this.handledMessages = tempHandled;
                    this.handledMessages.Clear();
                }
            }

            ClearMessages(this.currentMessages);
        }


        #endregion

        #endregion

    }
}
